package org.liveboardgames.agricola.business;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.liveboardgames.agricola.access.IFarmDao;
import org.liveboardgames.agricola.access.IFarmTileDao;
import org.liveboardgames.agricola.business.helper.GameHelper;
import org.liveboardgames.agricola.business.updater.FarmTileUpdater;
import org.liveboardgames.agricola.business.updater.FarmUpdater;
import org.liveboardgames.agricola.controller.AgricolaUpdateAdapter;
import org.liveboardgames.agricola.domain.Change;
import org.liveboardgames.agricola.domain.common.Peep;
import org.liveboardgames.agricola.domain.farm.Farm;
import org.liveboardgames.agricola.domain.farm.FarmTile;
import org.liveboardgames.agricola.domain.player.Player;
import org.liveboardgames.agricola.model.enums.FarmElementEnum;
import org.liveboardgames.agricola.model.enums.ResourceTypeEnum;

public class FarmServiceImpl implements IFarmService {

  private IFarmTileDao farmTileDao;

  private IFarmDao farmDao;

  public void setFarmTileDao(IFarmTileDao dao) {
    this.farmTileDao = dao;
  }

  public void setFarmDao(IFarmDao farmDao) {
    this.farmDao = farmDao;
  }

  private static final int NUMBER_OF_FARM_TILES = 15;

  public void addFarmElement(Long gameId, Long farmTileId, String farmElement) {
    FarmTile farmTile = farmTileDao.load(farmTileId);

    List<Change> changes = new ArrayList<Change>();
    new FarmTileUpdater(farmTile, changes).setFarmElement(farmElement);

    farmTileDao.save(farmTile);

    new AgricolaUpdateAdapter().publishGameUpdates(gameId, changes);
  }

  public void buildRoom(Long gameId, Long farmId, Integer numberOfRooms, Map<String, Integer> costPerRoom) {
    Farm farm = farmDao.load(farmId);

    List<Change> changes = new ArrayList<Change>();
    Map<String, Integer> cost = new HashMap<String, Integer>();
    for (String resourceType : costPerRoom.keySet()) {
      cost.put(resourceType, numberOfRooms * costPerRoom.get(resourceType));
    }
    new FarmUpdater(null, farm, changes).pay(cost);

    farmDao.save(farm);

    new AgricolaUpdateAdapter().publishGameUpdates(gameId, changes);
  }

  public void buildStable(Long gameId, Long farmId, Integer numberOfStables, Map<String, Integer> costPerStable) {
    Farm farm = farmDao.load(farmId);

    List<Change> changes = new ArrayList<Change>();
    Map<String, Integer> cost = new HashMap<String, Integer>();
    for (String resourceType : costPerStable.keySet()) {
      cost.put(resourceType, numberOfStables * costPerStable.get(resourceType));
    }
    new FarmUpdater(null, farm, changes).pay(cost);

    farmDao.save(farm);

    new AgricolaUpdateAdapter().publishGameUpdates(gameId, changes);
  }

  public void sow(Long gameId, Long farmId, String resourceType, Long tileId) {
    // Load the whole farm, since it will be needed for cards anyway
    Farm farm = farmDao.load(farmId);

    FarmTile tile = new GameHelper().findFarmTile(farm, tileId);

    List<Change> changes = new ArrayList<Change>();
    FarmTileUpdater updater = new FarmTileUpdater(tile, changes);
    if (ResourceTypeEnum.GRAIN.equalsIgnoreCase(resourceType)) {
      updater.addResource(resourceType, 3);
    }
    else if (ResourceTypeEnum.VEGETABLE.equalsIgnoreCase(resourceType)) {
      updater.addResource(resourceType, 2);
    }

    farmDao.save(farm);

    new AgricolaUpdateAdapter().publishGameUpdates(gameId, changes);
  }

  public void initializeFarm(Player player) {
    Farm farm = new Farm();
    initializeResources(farm);
    initializeTiles(player, farm);
    player.setFarm(farm);
  }

  private void initializeTiles(Player player, Farm farm) {
    List<FarmTile> tiles = new ArrayList<FarmTile>();

    // Create all the empty tiles
    for (int i = 0; i < NUMBER_OF_FARM_TILES; i++) {
      FarmTile farmTile = new FarmTile();
      farmTile.setFarm(farm);
      farmTile.setId(new Long(i));
      tiles.add(farmTile);
    }

    // Add the elements on them
    // - The rooms
    tiles.get(0).setFarmElement(FarmElementEnum.WOODEN_ROOM);
    tiles.get(1).setFarmElement(FarmElementEnum.WOODEN_ROOM);

    // - The peeps (the player has initially two peeps)
    int counter = 0;
    for (Iterator<Peep> iterator = player.getPeeps().iterator(); iterator.hasNext();) {
      Peep peep = iterator.next();
      tiles.get(counter++).addPeep(peep);
    }

    farm.setTiles(tiles);
  }

  private void initializeResources(Farm farm) {
    Map<String, Integer> resources = new HashMap<String, Integer>();
    resources.put(ResourceTypeEnum.FOOD, 3);
    farm.setResources(resources);
  }

}
